package com.nebula.salary.portal.config.security.component;

import com.nebula.salary.common.constants.Const;
import com.nebula.salary.common.result.ResponseCode;
import com.nebula.salary.common.utils.RedisUtil;
import com.nebula.salary.common.utils.SecurityUtil;
import com.nebula.salary.model.pojo.Role;
import com.nebula.salary.portal.service.IRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

/**
 * 权限控制
 * 判断用户角色
 *
 * @author codex
 * @since 2022-02-10
 */
@Component
public class CustomUrlDecisionManager implements AccessDecisionManager {
    
    @Autowired
    private IRoleService roleService;
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        for (ConfigAttribute configAttribute : configAttributes) {
            // 当前url所需角色
            String needRole = configAttribute.getAttribute();
    
            // 判断角色是否登录即可访问的角色，此角色再CustomFilter中设置
            if (Const.ROLE_LOGIN.equals(needRole)) {
                // 判断是否登录，此判断为未登录
                if (authentication instanceof AnonymousAuthenticationToken) {
                    throw new AccessDeniedException(ResponseCode.NEED_LOGIN.getDesc());
                } else {
                    return;
                }
            }
            
            // 判断用户角色是否为url所需角色
            // 获取用户角色所拥有的的权限
            try {
                String key = Const.LOGIN_USER_KEY + SecurityUtil.getUsername() + "_" + SecurityUtil.getUserId();
                
                Role role = redisUtil.getObject(key);
                if (role == null) {
                    role = roleService.getRolesByUserId(SecurityUtil.getUserId());
                    redisUtil.setObject(key, role, 365, TimeUnit.DAYS);
                }
                
                if (role != null && role.getRoleSecurity().equals(needRole)) {
                    return;
                }
                
            } catch (Exception ignored) {
            }
        }
    
        throw new AccessDeniedException(ResponseCode.FORBIDDEN.getDesc());
    }
    
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return false;
    }
    
    @Override
    public boolean supports(Class<?> clazz) {
        return false;
    }
}
